<?php
/**
 * 第三章 森林类
 * @author whq
 *
 */
require 'Tree.php';

class Forest implements Iterator , ArrayAccess
{

	/**
	 * 树木数组
	 * @var Tree array
	 */
	private $_tree;

	/**
	 * 森林实例
	 * @var Forest
	 */
	private static $_forest = null;

	/**
	 * 树木枯萎值
	 * @var int
	 */
	private $_died;

	/**
	 * 森林水资源
	 * @var int
	 */
	private $_water = 0;

	/**
	 * 森林死亡状态，0表示死了，1表示活着
	 * @var [0,1]
	 */
	private $_dieStatus = 1;

	/**
	 * 森林成长一次增加的水资源数量
	 * @var int
	 */
	const GROWTH_ADD_WATER = 10;

	/**
	 * 树木成长转换状态要消耗的水资源数量
	 * @var int
	 */
	const GROWTH_USE_WATER = 1;

	/**
	 * 类构造方法
	 * @access private
	 */
	private function __construct()
	{
		$this->_tree = array();
		$this->_ini();
	}

	/**
	 * 获取惟一实例
	 * @access public
	 * @return Forest
	 */
	public static function &getInstance()
	{
		if( self::$_forest == null )
		{
			self::$_forest = new Forest();
		}
		return self::$_forest;
	}

	/**
	 * 类初始化方法，在构造方法中调用
	 * @access private
	 */
	private function _ini()
	{
		$this->_tree[] = new Tree();
	}

	/**
	 * 定义森林的成长机制
	 * @return mixed
	 */
	public function grow()
	{
		$this->_water += Forest::GROWTH_ADD_WATER;
		if( count( $this->_tree ) === 0 )
		{
			return false;
		}
		foreach ( $this as $tree )
		{
			if( $tree->getDied() )
			{
				continue;
			}
			elseif( $tree->getWizened() )
			{
				/**
				 * 有30%的几率可以把干枯的树木，消耗2点水可以把树木救活，
				 * 但是本次森林的成长中，树木不会得到成长；
				 * 如果树木没有被救活，或者水依然不足，
				 * 则树木就会变成死亡状态。
				 */
				if( ( $this->_water >= 2 ) && ( rand( 0 , 9 ) < 3 ) )
				{
					$this->_water -= 2;
					$tree->setWizened( false );
				}
				else
				{
					$tree->setDied( true );
				}
			}
			else
			{
				/*	//原来的状态
				$oldStatus = $tree->getStatus();
				$tree->grow();
				//成长后的状态
				$newStatus = $tree->getStatus();*/
				//一棵树从一个状态，转换到另外一个状态时，需要消耗水
				$hadChangeStatus = $tree->grow();
				if( $hadChangeStatus )
				{
					//所剩的水不能满足树的成长需要，树变干枯
					//echo $tree->getStatus() ."<br />";
					if( $this->_water < Forest::GROWTH_USE_WATER )
					{
						// echo $tree->getStatus() ."<br />";
						$tree->setWizened( true );
						continue;
					}
					else
					{
						$this->_water -= Forest::GROWTH_USE_WATER;
					}
				}
				//每1颗结果后的树都会在森林中掉下一个种子
				if( $tree->getStatus() == Tree::HAD_GAINS && !$tree->getDied() && $tree->getGainsGrowthValue() == 0 && $hadChangeStatus )
				{
					$this->_tree[] = new Tree();
				}
			}
		}
	}

	/**
	 * 返回当前森林的树木数量
	 * @return int number
	 */
	public function getTreesNum()
	{
		return count( $this->_tree );
	}

	public function getWaterNum()
	{
		return $this->_water;
	}

	public static function getInformation( $forest = null )
	{
		$forest = $forest ? $forest : self::getInstance();
		echo "<br />森林的树木总量为：" . $forest->getTreesNum();
		echo "<br />森林的水总量为：" . $forest->getWaterNum();
		$seedCounter = $seedlingCounter = $littleTreeCounter = $bigTreeCounter = $gainTreeCounter = $wizenedCounter = $diedCounter = 0;
		foreach ( $forest as $tree )
		{
			switch( $tree->getStatus() )
			{
				case Tree::SEED:
					$seedCounter++;
					break;
				case Tree::SEEDLING:
					$seedlingCounter++;
					break;
				case Tree::LITTLE_TREE:
					$littleTreeCounter++;
					break;
				case Tree::BIG_TREE:
					$bigTreeCounter++;
					break;
				case Tree::HAD_GAINS:
					$gainTreeCounter++;
					break;
				default:
					return false;
					break;
			}
			if( $tree->getWizened() )
			{
				$wizenedCounter++;
			}
			if( $tree->getDied() )
			{
				$diedCounter++;
			}
		}
		echo "<br />森林的种子总量为：" . $seedCounter;
		echo "<br />森林的小苗总量为：" . $seedlingCounter;
		echo "<br />森林的小树总量为：" . $littleTreeCounter;
		echo "<br />森林的大树总量为：" . $bigTreeCounter;
		echo "<br />森林的结果树总量为：" . $gainTreeCounter;
		echo "<br />森林的枯树总量为：" . $wizenedCounter;
		echo "<br />森林的死树总量为：" . $diedCounter;
	}

	public function rewind()
	{
		reset( $this->_tree );
	}

	public function current()
	{
		return current( $this->_tree );
	}

	public function next()
	{
		return next( $this->_tree );
	}

	public function key()
	{
		return key( $this->_tree );
	}

	public function valid()
	{
		return $this->current() != false;
	}

	public function offsetExists( $offset )
	{
		return array_key_exists( $offset , $this->_tree );
	}

	public function offsetGet( $offset )
	{
		if( $this->offsetExists( $offset ) )
		{
			return $this->_tree[ $offset ];
		}
		return false;
	}

	public function offsetSet( $offset , $value )
	{
		if( $this->offsetExists( $offset ) )
		{
			$this->_tree[ $offset ] = $value;
		}
	}

	public function offsetUnset( $offset )
	{
		if( $this->offsetExists( $offset ) )
		{
			unset( $this->_tree[ $offset ] );
		}
	}

	public function __clone()
	{
		self::$_forest = $this;
	}
}

?>